#!/usr/bin/python
notice = """
Test Tool, 0.90
	copyright 2006 - all rights reserved
	Russell Y. Webb - rwebb@nthlab.com
-------------------------------------------------------

usage: ./test [Options] [files to test]

Runs all files with .sh and .vorpal extension and compares the 
output to matching .expected file in the same directory.

If no files are specified, then all files in TEST_PATH 
are tested.  The TEST_PATH defaults to 'src/test'.

Shell files are run with the directory set to the test directory.

Options:
	-v, --verbose: 
		show details of build
	-h, --help, --version: 
		print this information
	-b, --broken:
		run tests (in TEST_PATH/broken)
	-p, --path testing_path:
		set the TEST_PATH
"""

import os
import commands
import re
import sys

# run a shell command; exit on error; otherwise return result
def Shell(cmd, verbose = False):
	if verbose:
		print('--> % ' + cmd)
	outcome = commands.getstatusoutput(cmd)
	if outcome[0] != 0:
		print('    ... Error executing: ' + cmd)
		#sys.exit(0)
	return outcome

def FilterLines(excludeLine, append, str):
	result = ''
	for line in str.splitlines():
		if line.find(excludeLine) == -1:
			result += append + line + "\n"
	return result

# does a file exist
def Exists(path):
	return os.path.exists(path)

# return modification date
def ModDate(path):
	return os.path.getmtime(path)

# does a string match a pattern
def Match(pattern, str):
	return re.match(pattern, str) != None

# read a whole file
def ReadFile(path):
	f = file(path, 'r')
	s = f.read()
	f.close()
	return s

# write a whole file
def WriteFile(path, s):
	f = file(path, 'w')
	f.write(s)
	f.close()

def DoTest(path, names, verbose):
	results = {'pass':[], 'fail':[], 'no_expected':[]}
	for n in names:
		shell_test = Match('.+\.sh$', n)
		vorpal_test = Match('.+\.vorpal$', n)
		if shell_test or vorpal_test:
			base = re.findall('(.+)\..+', n)[0]
			expect = os.path.join(path, base + '.expected')
			tmp = os.path.join(path, base + '.result')
			error = 0
			print('Test: ' + base)
			
			if shell_test:
				result = FilterLines("completed with overhead", '', Shell('cd ' + path + '; ./' + n, verbose)[1])
				
			if vorpal_test:
				vorpal_src = os.path.join(path, n)
				result = FilterLines("completed with overhead", '', Shell('bin/vorpal ' + vorpal_src, verbose)[1])
			
			WriteFile(tmp, result)
			
			if error != 0:
				print('    ... FAILED')
				results['fail'].append(base)
			else:
				if Exists(expect):
					expected = FilterLines("completed with overhead", '', ReadFile(expect))
					if result != expected:
						print('    ... FAILED')
						diff_result = commands.getstatusoutput('diff ' + expect + ' ' + tmp)[1]
						print FilterLines("\ No newline at end of file", "\t", diff_result)
						results['fail'].append(base)
					else:
						Shell('rm ' + tmp)
						results['pass'].append(base)
				else:
					print('\tno ' + base + '.expected file')
					results['no_expected'].append(base)
			
	# print out which tests passed and which failed
	print "\n-------------------------------------------------------",
	if results['pass']:
		print "\nTests which PASS"
		for test in results['pass']:
			print "  + ", test
	
	if results['no_expected']:
		print "\nTests with no .expected file"
		for  test in results['no_expected']:
			print "  ? ", test
	
	if results['fail']:
		print "\nTests which FAIL"
		for test in results['fail']:
			print "  - ", test
		print "!!!!!!!!!!!! ################## !!!!!!!!!!!!!!! TESTS FAILED !!!!!!!!!!"
		print "!!!!!!!!!!!! ################## !!!!!!!!!!!!!!! TESTS FAILED !!!!!!!!!!"


verbose = False
broken = False
test_path = 'tests'
files = []
print("\n-------------------------------------------------------")
Shell("./build vorpal", True);

argi = 1
while argi < len(sys.argv):
	arg = sys.argv[argi]
	if arg == '--verbose' or arg == '-v':
		verbose = True
	elif arg == '-h' or arg == '--help' or arg == '--version':
		print(notice);
		sys.exit(0)
	elif arg == '-b' or arg == '--broken':
		broken = True
	elif arg == '-p' or arg == '--path':
		test_path = sys.argv[argi+1]
		argi += 1
	else:
		files.append(arg)
		
	argi += 1

# check path exists...
if not Exists(test_path):
	print("path does not exist")
	sys.exit(1)

# regular old method of just testing everything in the path...
if not files:
	if os.path.isdir(test_path):
		files = os.listdir(test_path)
		files.sort()
# new "test only x" method
else:
	for i in range(len(files)):
		# test files have can be vorpal or shell files
		if files[i].find(".vorpal") == -1 and files[i].find(".sh") == -1:
			files[i] += ".vorpal"

# test broken builds too
if broken:
	test_path = os.path.join(test_path, 'broken');
	print "\n==== BROKEN TESTS in " + test_path + "=======================================\n"
	DoTest(test_path, os.listdir(test_path), verbose)
else:
	DoTest(test_path, files, verbose)

